//Heyo, Frostii here. Almost all of the stuff that's *not* directly ported from 2.1 is in here, and is scripted by yours truly. 
//Please ask ina before taking any of this stuff for your own wads, it's really disrespectful to all the hard work we've done for 
//people to just steal our shit and use it without permission...
freeslot(
"MT_SOLEMERALD",
"MT_TRANSFORM_SOLEMERALD",
"S_SOLEMERALD1",
"S_SOLEMERALD2",
"S_SOLEMERALD3",
"S_SOLEMERALD4",
"S_SOLEMERALD5",
"S_SOLEMERALD6",
"S_SOLEMERALD7",
"MT_BLAZETAIL",
"MT_BLAZE_RUNFIRE",
"S_BLAZERUNFIRE",
"MT_BLAZE_JUMPFIRE",
"S_BLAZEJUMPFIRE",
"MT_BLAZEBOOSTAURA",
"S_BLAZEBOOSTAURA",
"MT_BLAZEBOOSTCIRCLE",
"S_BLAZEBOOSTCIRCLE",
"MT_BLAZEJUMPFLAME",
"S_BLAZEJUMPFLAME",
"MT_BLAZEBOOSTWIND",
"S_BLAZEBOOSTWIND",
"SPR_BLZF",
"SPR_BLZH",
"SPR_BSPF",
"SPR_BFPT",
"SPR_BJFR",
"SPR_INAE",
"SPR_BBCR",
"SPR_BWNE",
"S_BLAZETAIL_STAND",
"S_BLAZETAIL_SPRING",
"S_BLAZETAIL_FALL",
"S_BLAZETAIL_RUN",
"S_BLAZETAIL_INVIS",
"SFX_CATRL",
"SFX_BLZBST",
"SFX_BLZBTR",
"SFX_SECIR",
"SFX_SOLEMR",
"S_PLAY_BLAZE_HOVER",
"S_PLAY_BLAZE_SPINDASH",
"S_PLAY_BLAZE_SPIN",
"S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK",
"S_BPARTICLE",
"MT_BLAZE_SPINFIRE",
"S_BLAZESPINFIRE",
"MT_BLAZE_HOVERFIRE",
"S_BLAZEHOVERFIRE",
"MT_BLAZE_FLING",
"MT_BLAZE_DEADFLING",
"SPR_SEM1",
"SPR_SEM2",
"SPR_SEM3",
"SPR_SEM4",
"SPR_SEM5",
"SPR_SEM6",
"SPR_SEM7",
"SPR_BBFD"
)

local TWIRLSTATE = S_PLAY_ROLL

sfxinfo[sfx_blzbst].caption = "Boosting"
sfxinfo[sfx_blzbtr].caption = "/"
sfxinfo[sfx_solemr].caption = "Sol Emerald Collected"

mobjinfo[MT_BLAZEBOOSTWIND] = {
	doomednum = -1,
	spawnstate = S_BLAZEBOOSTWIND,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_BLAZEBOOSTWIND] = {
	sprite = SPR_BWNE,
	frame = A|FF_ANIMATE|TR_TRANS40|FF_PAPERSPRITE,
	var1 = 4,
	var2 = 4
}
mobjinfo[MT_SOLEMERALD] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SPECIAL,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
}
mobjinfo[MT_TRANSFORM_SOLEMERALD] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
}
mobjinfo[MT_BLAZETAIL] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOCLIPHEIGHT,
	dispoffset = 2,
	radius = 5*FRACUNIT,
	height = 5*FRACUNIT
}
mobjinfo[MT_BLAZEBOOSTAURA] = {
	doomednum = -1,
	spawnstate = S_BLAZEBOOSTAURA,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	dispoffset = 3,
	deathsound = sfx_ncspec
}
states[S_BLAZEBOOSTAURA] = {
	sprite = SPR_BBFD,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS30,
	var1 = 3,
	var2 = 1
}
mobjinfo[MT_BLAZEBOOSTCIRCLE] = {
	doomednum = -1,
	spawnstate = S_BLAZEBOOSTCIRCLE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_BLAZEBOOSTCIRCLE] = {
	sprite = SPR_BBCR,
	frame = FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|TR_TRANS60,
	var2 = 2
}
mobjinfo[MT_BLAZEJUMPFLAME] = {
	doomednum = -1,
	spawnstate = S_INVISIBLE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_BLAZE_RUNFIRE] = {
	doomednum = -1,
	spawnstate = S_BLAZERUNFIRE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_BLAZERUNFIRE] = {
	sprite = SPR_BLZF,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS30,
	var1 = 5,
	var2 = 1
}
mobjinfo[MT_BLAZE_JUMPFIRE] = {
	doomednum = -1,
	spawnstate = S_BLAZEJUMPFIRE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_BLAZEJUMPFIRE] = {
	sprite = SPR_BJFR,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS40,
	var1 = 5,
	var2 = 2
}
states[S_BPARTICLE] = {
	sprite = SPR_BFPT,
	frame = FF_FULLBRIGHT|A|TR_TRANS30,
}
mobjinfo[MT_BLAZE_SPINFIRE] = {
	doomednum = -1,
	spawnstate = S_BLAZESPINFIRE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 1*FRACUNIT,
	height = 1*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_BLAZESPINFIRE] = {
	sprite = SPR_BSPF,
	frame = FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|TR_TRANS30,
	var1 = 5,
	var2 = 1
}
mobjinfo[MT_BLAZE_HOVERFIRE] = {
	doomednum = 3445,
	spawnstate = S_BLAZEHOVERFIRE,
	flags = MF_NOGRAVITY|MF_NOCLIPHEIGHT,
	spawnhealth = 50,
	radius = 17*FRACUNIT,
	height = 34*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_BLAZE_FLING] = {
	doomednum = -1,
	spawnstate = S_PLAY_STND,
	flags = MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	deathstate = S_XPLD1,
	height = 5*FRACUNIT
}
mobjinfo[MT_BLAZE_DEADFLING] = {
	doomednum = -1,
	spawnstate = S_PLAY_STND,
	flags = MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	deathstate = S_NULL,
	height = 5*FRACUNIT
}
states[S_BLAZEHOVERFIRE] = {
	sprite = SPR_BLZH,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS30,
	var1 = 5,
	var2 = 1
}
states[S_SOLEMERALD1] = {
	sprite = SPR_SEM1,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD2] = {
	sprite = SPR_SEM2,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD3] = {
	sprite = SPR_SEM3,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD4] = {
	sprite = SPR_SEM4,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD5] = {
	sprite = SPR_SEM5,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD6] = {
	sprite = SPR_SEM6,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD7] = {
	sprite = SPR_SEM7,
	frame = FF_FULLBRIGHT|A
}

local waterfactor = function(mo)
	if mo.eflags&MFE_UNDERWATER
		return 2
	end
	return 1
end

--inazuma here. first off we do a little bit of trolling. this is for 2.2.9's additive effect thingies. This basically turns it on or something.
local function set_add(mo) mo.blendmode = AST_ADD end

// Lach: self-explanatory
local function FixedSquare(n)
	return FixedMul(n, n)
end

// Lach: port of FV3_Rotate from source
local function FV3_Rotate(rotVecX, rotVecY, rotVecZ, axisVecX, axisVecY, axisVecZ, angle)
	local ux, uy, uz = FixedMul(axisVecX, rotVecX), FixedMul(axisVecX, rotVecY), FixedMul(axisVecX, rotVecZ)
	local vx, vy, vz = FixedMul(axisVecY, rotVecX), FixedMul(axisVecY, rotVecY), FixedMul(axisVecY, rotVecZ)
	local wx, wy, wz = FixedMul(axisVecZ, rotVecX), FixedMul(axisVecZ, rotVecY), FixedMul(axisVecZ, rotVecZ)
	local sa, ca = sin(angle), cos(angle)
	local ua = ux + vy + wz
	local ax, ay, az = FixedMul(axisVecX, ua), FixedMul(axisVecY, ua), FixedMul(axisVecZ, ua)
	local xs, ys, zs = FixedSquare(axisVecX), FixedSquare(axisVecY), FixedSquare(axisVecZ)
	local bx, by, bz = FixedMul(rotVecX, ys + zs), FixedMul(rotVecY, xs + zs), FixedMul(rotVecZ, xs + ys)
	local cx, cy, cz = FixedMul(axisVecX, vy + wz), FixedMul(axisVecY, ux + wz), FixedMul(axisVecZ, ux + vy)
	local dx, dy, dz = FixedMul(bx - cx, ca), FixedMul(by - cy, ca), FixedMul(bz - cz, ca)
	local ex, ey, ez = FixedMul(vz - wy, sa), FixedMul(wx - uz, sa), FixedMul(uy - vx, sa)
	
	return ax + dx + ex, ay + dy + ey, az + dz + ez
end

// Lach: translate object's momx/momy into 3-dimensional vector based on slope
local function GetMobjMovementVector(mo)
	local slope = mo.standingslope
	
	if slope
	and slope.zangle ~= 0
		return FV3_Rotate(mo.momx, mo.momy, 0, -slope.d.y, slope.d.x, 0, slope.zangle)
	end
	
	return mo.momx, mo.momy, mo.momz
end

//katsy: global function to get p speed depending on 2d mode
rawset(_G, "getrushcharpspeed", function(player)
	if twodlevel or (player.revi and (player.mo.flags2 & MF2_TWOD))
		return FixedMul(player.runspeed*2/3, player.mo.scale)
	else
		return FixedMul(player.runspeed, player.mo.scale)
	end
end)
	
--first off, some PreThink stuff. most of this may not actually need to be in a PreThink, they're all just here to be safe.
addHook("PreThinkFrame", function(phuckshit)
	for p in players.iterate
		if p.mo and p.mo.skin == "blaze"
			if p.fakenormalspeed == nil
				p.fakenormalspeed = skins[p.mo.skin].normalspeed
			end
			
			if p.blazelastspeed == nil
				p.blazelastspeed = p.speed
				p.blazelastz = p.mo.z
				p.blazelastx = p.mo.x
				p.blazelasty = p.mo.y
				p.blazeburstcharge = 0
				p.blazespindown = false
			end

			if P_IsObjectOnGround(p.mo) or (p.mo.eflags & MFE_JUSTHITFLOOR)
			or (p.powers[pw_carry]) or p.powers[pw_nocontrol]
			or P_PlayerInPain(p) or not p.mo.health or p.powers[pw_super] == 1
			or (p.solchar and p.solchar.istransformed == 1)
				p.blazehover = false
				p.blazehoverpower = 0
				p.blazehovertimer = 88
				p.mo.blazejumping = 0
			end

			if p.powers[pw_nocontrol] return end
			
			if p.dashspeed > 0 
				p.pflags = $ & ~ PF_THOKKED
			end
			
			if p.speed > FixedMul(4*FRACUNIT+FRACUNIT/2, p.mo.scale) and not (p.powers[pw_carry] == CR_ZOOMTUBE)
				if p.mo.eflags & MFE_SPRUNG and P_IsObjectOnGround(p.mo) and (p.blazelaststate == TWIRLSTATE or p.blazelaststate == S_PLAY_BLAZE_SPIN)
					p.mo.state = TWIRLSTATE
				end
			end
			
			//katsy: allow blaze to spin with down input in 2d mode
			if not (p.pflags & PF_SPINNING) and ((twodlevel) or (p.mo.flags2 & MF2_TWOD))
			and P_IsObjectOnGround(p.mo) and (p.cmd.forwardmove < -20) and (p.speed > FixedMul(5<<FRACBITS, p.mo.scale))
				p.mo.state = TWIRLSTATE
				S_StartSound(p.mo, sfx_spin)
				p.pflags = $|PF_SPINNING|PF_SPINDOWN
			end
			
			--blaze spin-momentum.
			--MOSTLY-stolen from VEPH because fuck if i know how to code this shit on my own
			if p.pflags & PF_SPINNING and not p.powers[pw_carry]
			and not (p.pflags & PF_STASIS)
				--transition air spin into a jump!
				if not P_IsObjectOnGround(p.mo)
					p.pflags = $|PF_THOKKED & ~PF_NOJUMPDAMAGE
					
				--the actual special code
				else
					--spawn afterimages
					if p.mo.state == S_PLAY_BLAZE_SPIN
					or p.mo.state == S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK
						P_SpawnSpinMobj(p, MT_THOK)
					else
						local ghostmobj = P_SpawnGhostMobj(p.mo)
						ghostmobj.blendmode = AST_ADD
						ghostmobj.colorized = true
						ghostmobj.color = p.blazeflamecolor
						ghostmobj.fuse = 0
						ghostmobj.tics = 3
						ghostmobj.frame = $ & ~FF_TRANSMASK | FF_TRANS50
						ghostmobj.destscale = 0
						ghostmobj.scalespeed = p.mo.scale/12
						if ghostmobj.tracer and ghostmobj.tracer.valid
							ghostmobj.tracer.blendmode = AST_ADD
							ghostmobj.tracer.colorized = true
							ghostmobj.tracer.color = p.blazeflamecolor
							ghostmobj.tracer.fuse = 0
							ghostmobj.tracer.tics = 3
							ghostmobj.tracer.frame = $ & ~FF_TRANSMASK | FF_TRANS50
							ghostmobj.tracer.destscale = 0
							ghostmobj.tracer.scalespeed = p.mo.scale/12
						end
					end
					
					--the fun stuff
					local oldmomx = p.mo.momx
					local oldmomy = p.mo.momy
					local oldspeed = R_PointToDist2(0,0, oldmomx, oldmomy)
					local factor = max(max(81 - oldspeed*3/p.mo.scale, 12) - max(oldspeed*2/3/p.mo.scale - 36, 0), 6)
					
					local angle = p.cmd.angleturn<<16
					if p.mo.flags2 & MF2_TWOD or twodlevel
						angle = ANGLE_90
					end
					
					P_Thrust(p.mo, angle, p.cmd.forwardmove*p.mo.scale/factor)
					P_Thrust(p.mo, angle+ANGLE_90, -p.cmd.sidemove*p.mo.scale/factor)
					
					if R_PointToDist2(0,0, p.mo.momx, p.mo.momy) > oldspeed
						P_InstaThrust(p.mo, R_PointToAngle2(0,0, p.mo.momx, p.mo.momy), oldspeed)
					end
				end
			end
			
			p.blazelastspeed = p.speed
			p.blazelastz = p.mo.z
			p.blazelastx = p.mo.x
			p.blazelasty = p.mo.y
			p.blazelaststate = p.mo.state
		end
		p.blazespindown = (p.cmd.buttons & BT_SPIN)
	end
end)
addHook("PlayerSpawn", function(p)
	p.blazeburstcharge = 0
end)

--attacking while spinning or burning
addHook("PlayerCanDamage", function(p)
	if p.mo and p.mo.skin == "blaze"
		if p.mo.state == TWIRLSTATE or p.mo.state == S_PLAY_BLAZE_SPIN or p.mo.state == S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK or (p.blazeboosting)
			return true
		end
		if p.blazespindash and not p.solchar.istransformed
			return false
		end
	end
end)

--start a spin
addHook("SpinSpecial", function(p)
	if p.mo and p.mo.skin == "blaze" and not (p.powers[pw_carry])
		if P_IsObjectOnGround(p.mo) and not (p.powers[pw_carry] == CR_ZOOMTUBE) and p.speed > FixedMul(4*FRACUNIT+FRACUNIT/2, p.mo.scale)
			if not (p.blazeburstcharge > TICRATE*2) or p.gotflag or p.gotflagdebuff or p.gotcrystal
				if not (p.pflags & PF_SPINDOWN) or (p.mo.eflags & MFE_JUSTHITFLOOR)
					if p.mo.state == S_PLAY_WALK or p.mo.state == S_PLAY_RUN or (p.mo.eflags & MFE_JUSTHITFLOOR)
						p.mo.state = TWIRLSTATE
						S_StartSound(p.mo, sfx_spin)
						p.pflags = $|PF_SPINNING|PF_SPINDOWN
						return true
					end
				end
			elseif not (p.mo.state == S_PLAY_ROLL and (p.pflags & PF_SPINDOWN))  and not (p.mo.eflags & MFE_JUSTHITFLOOR)
				if not (p.blazeboosting)
					S_StartSound(p.mo, sfx_blzbst)
					p.blazeboosttimer = 1
				end
				if p.mo.state == S_PLAY_ROLL
					p.mo.state = S_PLAY_RUN
				end
				p.blazeboosting = true
			end
		end
	end
end)

--main thinker
addHook("PlayerThink", function(p)
	if p.mo and p.mo.skin == "blaze"
		local mo = p.mo
		
		--air control stuff
		if p.mo.blazejumping or p.blazehover
			if p.mo.blazejumping
				p.thrustfactor = 9
			end
			if p.blazehover
				p.thrustfactor = 4
			end
		else
			p.thrustfactor = skins[p.mo.skin].thrustfactor
		end
		
		if not P_IsObjectOnGround(p.mo)
			p.blassped = FixedHypot(p.mo.momx, p.mo.momy)
		else
			p.blassped = nil
		end
		
		if (p.pflags & PF_STARTDASH) and not p.blazespindash
			p.pflags = $ & ~ PF_STARTDASH
		end
		
		if p.powers[pw_carry] == CR_MACESPIN
			p.mo.state = S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK
		end
		
		if p.mo.blazeinspingap != nil and p.mo.blazeinspingap > 0
			p.mo.blazeinspingap = $ - 1
		end
		
		if p.mo.state == S_PLAY_BLAZE_SPIN and p.mo.blazeinspingap != nil and p.mo.blazeinspingap == 0
			p.mo.state = S_PLAY_ROLL
		end
		
		if not ((p.pflags & PF_THOKKED) and (p.pflags & PF_JUMPED) and (mo.state == S_PLAY_JUMP))
			mo.blazejumping = 0
		end
		
		if mo.blazejumping
			mo.blazejumping = $+1
			if mo.blazejumping < 10
				P_SetObjectMomZ(p.mo, FRACUNIT * 9/4 / waterfactor(mo), true)
			elseif mo.blazejumping > 40
				mo.blazejumping = 0
			end
		end
		--some funny haha fire FX for runnin'
		local fuckunit = p.mo.scale
		if P_IsObjectOnGround(p.mo) and (p.speed > getrushcharpspeed(p))
		and (p.panim == PA_RUN or p.panim == PA_ROLL) and not p.powers[pw_carry]
			if leveltime % 2 == 0
				local fire1 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.drawangle+FixedAngle(160*FRACUNIT), 20*FRACUNIT), P_ReturnThrustY(p.drawangle+FixedAngle(160*FRACUNIT), 20*FRACUNIT), 0, MT_BLAZE_RUNFIRE)
				if p.mo.eflags & MFE_UNDERWATER
					fire1.state = S_PARTICLE
					fire1.destscale = 7*p.mo.scale
				end
				fire1.color = p.blazeflamecolor
				fire1.fuse = 6
				P_SetObjectMomZ(fire1, 2*fuckunit+fuckunit/2, false)
				fire1.momx = p.mo.momx*3/4
				fire1.momy = p.mo.momy*3/4
				P_Thrust(fire1, R_PointToAngle2(p.mo.x, p.mo.y, fire1.x, fire1.y), 5*fuckunit)
				fire1.angle = R_PointToAngle2(p.mo.x, p.mo.y, fire1.x, fire1.y)
				fire1.scale = p.mo.scale - p.mo.scale/5
				local fire2 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.drawangle+FixedAngle(200*FRACUNIT), 20*FRACUNIT), P_ReturnThrustY(p.drawangle+FixedAngle(200*FRACUNIT), 20*FRACUNIT), 0, MT_BLAZE_RUNFIRE)
				if p.mo.eflags & MFE_UNDERWATER
					fire2.state = S_PARTICLE
					fire2.destscale = 7*p.mo.scale
				end
				fire2.color = p.blazeflamecolor
				fire2.fuse = 6
				P_SetObjectMomZ(fire2, 2*fuckunit+fuckunit/2, false)
				fire2.momx = p.mo.momx*3/4
				fire2.momy = p.mo.momy*3/4
				P_Thrust(fire2, R_PointToAngle2(p.mo.x, p.mo.y, fire2.x, fire2.y), 5*fuckunit)
				fire2.angle = R_PointToAngle2(p.mo.x, p.mo.y, fire2.x, fire2.y)
				fire2.scale = p.mo.scale - p.mo.scale/5
			end
		end
		--hover
		if p.blazehover
		and not (P_IsObjectOnGround(p.mo) or (p.mo.eflags & MFE_JUSTHITFLOOR)
		or (p.powers[pw_carry]) or p.powers[pw_nocontrol]
		or P_PlayerInPain(p) or not p.mo.health or p.powers[pw_super] == 1
		or (p.solchar and p.solchar.istransformed == 1))
			if p.cmd.buttons & BT_JUMP and (p.pflags & PF_JUMPED) and p.blazehovertimer > 0
				if not p.blazehoverpower
					p.blazehoverpower = 0
				end
				if (p.solchar.istransformed)
					p.blazehoverpower = FRACUNIT*3
				end
				if p.mo.momz*P_MobjFlip(p.mo) <= p.blazehoverpower
					p.blazehoverpower = $ - FRACUNIT/15
					p.blazehovertimer = $ - 1
					P_SetObjectMomZ(p.mo, p.blazehoverpower, false)
				end
				if (p.mo.state != S_PLAY_BLAZE_HOVER) and not (p.mo.state == S_PLAY_RUN and p.blazeboosting)
					p.mo.state = S_PLAY_BLAZE_HOVER
				end
				--flames
				local fuckunit = mo.scale
				local dist = 19
				local apart = 8
				local zheight = 4
				if not (p.flame1 and p.flame1.valid) and not (p.flame2 and p.flame2.valid)--leveltime % 7 == 0
					local flame1 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(flame1, p.drawangle+FixedAngle(180*FRACUNIT), dist*FRACUNIT)+
					P_ReturnThrustX(flame1, p.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
					P_ReturnThrustY(flame1, p.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
					P_ReturnThrustX(flame1, p.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
					-zheight*fuckunit*P_MobjFlip(p.mo), MT_BLAZE_HOVERFIRE)
					flame1.invuln = 7
					flame1.color = p.blazeflamecolor
					flame1.target = p.mo
					flame1.flame1 = true
					flame1.scale = p.mo.scale --+ p.mo.scale/4
					p.flame1 = flame1
					local flame2 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(flame2, p.drawangle+FixedAngle(180*FRACUNIT), dist*FRACUNIT)+
					P_ReturnThrustX(flame1, p.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit),
					P_ReturnThrustY(flame2, p.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
					P_ReturnThrustY(flame1, p.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
					-zheight*fuckunit*P_MobjFlip(p.mo), MT_BLAZE_HOVERFIRE)
					flame2.invuln = 7
					flame2.color = p.blazeflamecolor
					flame2.target = p.mo
					flame2.flame2 = true
					flame2.scale = p.mo.scale --+ p.mo.scale/4
					p.flame2 = flame2			 
				end
			elseif not P_PlayerInPain(p)
				p.mo.state = S_PLAY_FALL
				p.blazehover = false
			end
		else
			if S_SoundPlaying(p.mo, sfx_blzhvr)
				S_StopSoundByID(p.mo, sfx_blzhvr)
			end
		end
		
		--spindash
		if p.blazespindash or (CBW_Battle and p.actionstate == 1)
			if not (p.mo.eflags & MFE_UNDERWATER)
				if leveltime % 5 == 0
					--print("phuck")
					local spin1 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.mo, p.drawangle+FixedAngle(140*FRACUNIT), 25*FRACUNIT), P_ReturnThrustY(p.mo, p.drawangle+FixedAngle(140*FRACUNIT), 25*FRACUNIT), 0, MT_BLAZE_SPINFIRE)
					spin1.fuse = 5
					spin1.angle = R_PointToAngle2(spin1.x, spin1.y, p.mo.x, p.mo.y)
					spin1.spin1 = true
					spin1.target = p.mo
					spin1.color = p.blazeflamecolor
					local spin2 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.mo, p.drawangle+FixedAngle(220*FRACUNIT), 25*FRACUNIT), P_ReturnThrustY(p.mo, p.drawangle+FixedAngle(220*FRACUNIT), 25*FRACUNIT), 0, MT_BLAZE_SPINFIRE)
					spin2.fuse = 5
					spin2.angle = R_PointToAngle2(spin2.x, spin2.y, p.mo.x, p.mo.y)
					spin2.spin2 = true
					spin2.target = p.mo
					spin2.color = p.blazeflamecolor
				end
			else
				local i = 0 while i <= (leveltime%7)/2 // 1, 2, 3 or 4 particles
					local particle = P_SpawnMobj(p.mo.x, p.mo.y, p.mo.z, MT_SMALLBUBBLE)
					particle.fuse = 25
					particle.target = p.mo
					particle.destscale = (2*FRACUNIT)/3
					P_SetScale(particle, particle.destscale)
					if (p.mo.eflags & MFE_VERTICALFLIP) // readjust z position if needed
						particle.z = p.mo.z + p.mo.height - particle.height
					end
					local prandom = {}
					prandom[0] = P_RandomFixed()<<2 // P_RandomByte()<<10
					prandom[1] = P_RandomRange(-30, 30) // P_RandomRange(-ANG30/FRACUNIT, ANG30/FRACUNIT)*FRACUNIT
					prandom[2] = P_RandomFixed()<<3 // P_RandomByte()<<11
					P_SetObjectMomZ(particle, p.dashspeed/50 + prandom[0], false)
					P_InstaThrust(particle,
							p.mo.angle + (prandom[1]*ANG1),
							-FixedMul(p.dashspeed/12 + FRACUNIT + prandom[2], p.mo.scale))
					P_TryMove(particle, particle.x+particle.momx, particle.y+particle.momy, true)
				
					i = $+1
				end
			end
		end
		--burst mode
		if P_PlayerInPain(p) or (p.cmd.buttons & BT_CUSTOM1)
		or p.gotflag or p.gotflagdebuff or p.gotcrystal or p.powers[pw_super] == 1
		or (p.solchar and p.solchar.istransformed == 1) or p.exiting
		or p.powers[pw_carry] == CR_NIGHTSMODE
			if p.blazeburstcharge >= TICRATE*2
				S_StartSound(p.mo, sfx_s1ab)
			end
			p.blazeburstcharge = 0
		elseif (FixedHypot(p.rmomx, p.rmomy) > getrushcharpspeed(p)) and ((p.pflags & PF_JUMPED) or (P_IsObjectOnGround(p.mo)))
			p.blazeburstcharge = $+(TICRATE/35)
			if (p.solchar and p.solchar.istransformed) and (p.blazeburstcharge < TICRATE*2)
				p.blazeburstcharge = $+(TICRATE/35)
			end
			if not (leveltime%2) and (FixedHypot(p.rmomx, p.rmomy) > FixedMul(52<<FRACBITS, p.mo.scale)) and (p.blazeburstcharge < TICRATE*2)
				p.blazeburstcharge = $+(TICRATE/35) //charge 1.5x faster at high speeds
			end
		elseif P_IsObjectOnGround(p.mo) or (p.mo.eflags & MFE_JUSTHITFLOOR)
			if p.blazeburstcharge >= TICRATE*2
				S_StartSound(p.mo, sfx_s1ab)
			end
			p.blazeburstcharge = 0
		end
		if (p.blazeburstcharge >= TICRATE*2)
			if (p.blazeburstcharge == TICRATE*2)
				S_StartSound(p.mo, sfx_prloop)
			end
			--print(p.blazeburstcharge)
		end
		if (p.mo.boat and p.mo.boat.valid and p.mo.boat.health)
			p.blazeburstcharge = 0
		end
		p.pflags = $ & ~PF_DRILLING
		if (p.blazeboosting)
			if not (p.cmd.buttons & BT_SPIN) or (p.blazeburstcharge < TICRATE*2)
			or (p.skidtime > 0) or (p.powers[pw_carry])
			or (FixedHypot(p.mo.momx, p.mo.momy) <= 20*p.mo.scale and not P_IsObjectOnGround(p.mo))
				p.blazeboosting = false
				p.charflags = $&~SF_RUNONWATER
				if (p.solchar and p.solchar.istransformed)
					p.jumpfactor = FRACUNIT+FRACUNIT/3
				else
					p.jumpfactor = FRACUNIT
				end
				--p.hasnomomentum = false
			else
				local momx, momy, momz = GetMobjMovementVector(p.mo)
				p.charflags = $|SF_RUNONWATER
				p.pflags = $|PF_DRILLING & ~PF_SPINNING
				if p == displayplayer and not splitscreen
					P_StartQuake(FRACUNIT, 3)
				end
				local blazewind = P_SpawnMobjFromMobj(p.mo, P_RandomRange(-50, 50)*FRACUNIT, P_RandomRange(-50, 50)*FRACUNIT, P_RandomRange(0, 58)*FRACUNIT, MT_BLAZEBOOSTWIND)					
				blazewind.fuse = 20
				blazewind.momx = momx-momx/3
				blazewind.momy = momy-momy/3
				blazewind.momz = momz-momz/3
				blazewind.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.x+p.mo.momx, p.mo.y+p.mo.momy)
				blazewind.color = SKINCOLOR_NEON
				blazewind.scale = p.mo.scale+p.mo.scale/2
				blazewind.blendmode = AST_ADD
				if p.solchar.istransformed or p.powers[pw_sneakers]
					if FixedHypot(p.mo.momx, p.mo.momy) <= 80*p.mo.scale --more accurate player.speed
						P_Thrust(p.mo, p.mo.angle, 80*p.mo.scale-FixedHypot(p.mo.momx, p.mo.momy))
					end
				else
					if FixedHypot(p.mo.momx, p.mo.momy) <= 60*p.mo.scale --more accurate player.speed
						P_Thrust(p.mo, p.mo.angle, 60*p.mo.scale-FixedHypot(p.mo.momx, p.mo.momy))
					end
				end
				if not (p.blazeboostmobj and p.blazeboostmobj.valid)
					local boost = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.mo, R_PointToAngle2(p.mo.x, p.mo.y, p.mo.x+p.mo.momx, p.mo.y+p.mo.momy), 5*FRACUNIT), P_ReturnThrustY(p.mo, R_PointToAngle2(p.mo.x, p.mo.y, p.mo.x+p.mo.momx, p.mo.y+p.mo.momy), 5*FRACUNIT), 0, MT_BLAZEBOOSTAURA)
					boost.target = p.mo
					boost.color = p.blazeflamecolor
					p.blazeboostmobj = boost
				end
				if p.blazeboosttimer and p.blazeboosttimer % 15 == 0
					local circle = P_SpawnMobjFromMobj(p.mo, 0, 0, p.mo.height, MT_BLAZEBOOSTCIRCLE)
					circle.momx = momx/2
					circle.momy = momy/2
					circle.momz = momz/2
					circle.color = p.blazeflamecolor
					circle.fuse = 20
					circle.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.momx+p.mo.x, p.mo.momy+p.mo.y)+FixedAngle(90*FRACUNIT)
					circle.destscale = p.mo.scale*25
					circle.scalespeed = p.mo.scale/26
					circle.blendmode = AST_ADD
				end
				if not (p.solchar and p.solchar.istransformed)
					p.jumpfactor = FRACUNIT+FRACUNIT/3
				else
					p.jumpfactor = FRACUNIT*2
				end
				p.drawangle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.x+p.mo.momx, p.mo.y+p.mo.momy)
				if p.blazeboosttimer % (TICRATE+TICRATE/2) == 4
					S_StartSound(p.mo, sfx_blzbtr)
				end
				p.blazeboosttimer = $+1
				--p.hasnomomentum = true
			end
		else
			if S_SoundPlaying(p.mo, sfx_blzbtr)
				S_StopSoundByID(p.mo, sfx_blzbtr)
			end
		end
	end
end)
--yoinking a bit of code from lach since layering bs is dumb
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health
		if mo.target and mo.target.valid and mo.target.health and mo.target.skin == "blaze" and mo.target.player.blazeboosting
		local cameraToPlayerAngle = R_PointToAngle(mo.target.x, mo.target.y)
		if camera then cameraToPlayerAngle = R_PointToAngle2(camera.x + camera.momx, camera.y + camera.momy, mo.target.x, mo.target.y) end
		local rotation = ((cameraToPlayerAngle - mo.target.player.drawangle + ANGLE_202h) >> 29) + 1 // this gives us the frame rotation number for an 8-angle frame, as written in source 
		--P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.target.y+P_ReturnThrustY(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.target.z)
		if rotation != 5
			P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo.target, mo.target.player.drawangle, 5*mo.target.scale)+P_ReturnThrustX(mo, displayplayer.cmd.angleturn<<16, -6*mo.target.scale), mo.target.y+P_ReturnThrustY(mo.target, mo.target.player.drawangle, 5*mo.target.scale)+P_ReturnThrustY(mo.target, displayplayer.cmd.angleturn<<16, -6*mo.target.scale), mo.target.z)
		else
			P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo.target, mo.target.player.drawangle, 2*mo.target.scale), mo.target.y+P_ReturnThrustY(mo.target, mo.target.player.drawangle, 2*mo.target.scale), mo.target.z)
		end
		--P_TeleportMove(mo, mo.x+P_ReturnThrustX(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.y+P_ReturnThrustY(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.z)
		if (mo.eflags & MFE_VERTICALFLIP)
			mo.z = mo.target.z+(mo.target.height/2)
		end
		mo.rollangle = mo.target.rollangle
		mo.angle = mo.target.player.drawangle --R_PointToAngle2(mo.target.x, mo.target.y, mo.target.x+mo.target.momx, mo.target.y+mo.target.momy)
		mo.scale = mo.target.scale
		mo.spritexscale = FRACUNIT+FRACUNIT/2
		mo.spriteyscale = FRACUNIT+FRACUNIT/2
		--mo.state = mo.target.state
		--mo.frame = mo.target.frame|TR_TRANS30
		--mo.spritexscale = FRACUNIT/2
		--mo.spriteyscale = FRACUNIT/2
		else
			P_RemoveMobj(mo)
		end
	end
end, MT_BLAZEBOOSTAURA)

addHook("MobjThinker", function(mo)
	if mo.target and mo.target.valid
		if mo.BlazeSpecialGhost
			--P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.target.y+P_ReturnThrustY(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.target.z)
			if not (mo.FuckYouScoobyDoo)
				P_TeleportMove(mo, mo.target.x, mo.target.y, mo.target.z)
			else
				P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle, mo.target.scale*3*-1), mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle, mo.target.scale*3*-1), mo.target.z)
			end
			mo.rollangle = mo.target.rollangle
			mo.angle = mo.target.player.drawangle
			--mo.state = mo.target.state
			--mo.frame = mo.target.frame|TR_TRANS30
		end
	end
end, MT_GHOST)

--do a normal roll in a zoomtube
addHook("ThinkFrame", do
	for player in players.iterate do
		if player.mo and player.mo.skin == "blaze"
		and player.powers[pw_carry] == CR_ZOOMTUBE then
			//if not in the animation, set it
			if not (player.mo.state == S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK) then
				player.mo.state = S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK
			end
			//set panim so the zoomtube doesn't change to rolling
			player.panim = PA_ROLL
		end
	end
end)

--spin fire thinker
addHook("MobjThinker", function(mo)
	if mo.target and mo.target.valid and mo.target.health
		local pmo = mo.target
		local p = mo.target.player
		local scale = mo.target.scale
		if (pmo.flags2 & MF2_OBJECTFLIP)
			mo.flags2 = $ | MF2_OBJECTFLIP
		else
			mo.flags2 = $ & ~ MF2_OBJECTFLIP
		end
		if not (pmo.flags2 & MF2_OBJECTFLIP)
			if mo.spin1
				P_TeleportMove(mo, pmo.x+P_ReturnThrustX(pmo, p.drawangle+FixedAngle(140*FRACUNIT), 25*scale), pmo.y+P_ReturnThrustY(pmo, p.drawangle+FixedAngle(140*FRACUNIT), 25*scale), pmo.z)
				mo.angle = R_PointToAngle2(mo.x, mo.y, pmo.x, pmo.y)
			elseif mo.spin2
				P_TeleportMove(mo, pmo.x+P_ReturnThrustX(pmo, p.drawangle+FixedAngle(220*FRACUNIT), 25*scale), pmo.y+P_ReturnThrustY(pmo, p.drawangle+FixedAngle(220*FRACUNIT), 25*scale), pmo.z)
				mo.angle = R_PointToAngle2(mo.x, mo.y, pmo.x, pmo.y)
			end
		else
			if mo.spin1
				P_TeleportMove(mo, pmo.x+P_ReturnThrustX(pmo, p.drawangle+FixedAngle(140*FRACUNIT), 25*scale), pmo.y+P_ReturnThrustY(pmo, p.drawangle+FixedAngle(140*FRACUNIT), 25*scale), pmo.z+ mo.target.height - mo.height)
				mo.angle = R_PointToAngle2(mo.x, mo.y, pmo.x, pmo.y)
			elseif mo.spin2
				P_TeleportMove(mo, pmo.x+P_ReturnThrustX(pmo, p.drawangle+FixedAngle(220*FRACUNIT), 25*scale), pmo.y+P_ReturnThrustY(pmo, p.drawangle+FixedAngle(220*FRACUNIT), 25*scale), pmo.z+ mo.target.height - mo.height)
				mo.angle = R_PointToAngle2(mo.x, mo.y, pmo.x, pmo.y)
			end
		end
		if not (p.blazespindash or (CBW_Battle and p.actionstate == 1))
			P_RemoveMobj(mo)
		end
	end
end, MT_BLAZE_SPINFIRE)

--start double jump/hover
addHook("AbilitySpecial", function(p)
	if p.mo.skin == "blaze" and p.gotflag <= 0
	and not (p.gotflagdebuff) and not p.gotcrystal
		local mo = p.mo
		if p.exiting return end
		if (p.pflags & PF_THOKKED)
			if p.blazehovertimer and p.blazehovertimer > 0
				p.blazehover = true
				mo.state = S_PLAY_BLAZE_HOVER
				p.pflags = $|PF_JUMPED|PF_NOJUMPDAMAGE & ~PF_SPINNING
				S_StartSound(mo, sfx_blzhvr)
				p.blazehovertimer = max(0, $ - 9)
				
				mo.momz = $ / 2
			end
		else
			if p == displayplayer and not splitscreen
				P_StartQuake(2*FRACUNIT, 10)
			end
			
			local jumpheight = -2*FRACUNIT / waterfactor(mo)
			P_SetObjectMomZ(p.mo, jumpheight, false)
			
			p.pflags = $|PF_JUMPED|PF_THOKKED & ~PF_SPINNING & ~PF_NOJUMPDAMAGE
			mo.state = S_PLAY_JUMP
			mo.blazejumping = 1
			S_StartSound(mo, sfx_blzjmp)
		end
	end
end)

--hover fire thinker
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health and mo.target and mo.target.health and mo.target.valid
		if mo.target.flags2 & MF2_OBJECTFLIP
			mo.flags2 = $ | MF2_OBJECTFLIP
			mo.eflags = $ | MFE_VERTICALFLIP
		else
			mo.flags2 = $ & ~ MF2_OBJECTFLIP
			mo.eflags = $ & ~ MFE_VERTICALFLIP
		end
		mo.scale = mo.target.scale

		local fuckunit = mo.scale
		local dist = 19
		local apart = 8
		local zheight = 4
		if not (mo.flags2 & MF2_OBJECTFLIP)
			if mo.flame1
				P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
				mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
				mo.target.z-zheight*fuckunit)
			elseif mo.flame2
				P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
				mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
				mo.target.z-zheight*fuckunit)
			end
		else--eaeaeaea
			if mo.flame1
				P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
				mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
				mo.target.z+zheight*fuckunit + mo.target.height - mo.height)
			elseif mo.flame2
				P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
				mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
				mo.target.z+zheight*fuckunit + mo.target.height - mo.height)
			end
		end
		
		if mo.invuln > 0 
			mo.invuln = $ - 1
		end

		if mo.invuln == 0 and mo.frame & FF_FRAMEMASK == A
			mo.frame = B | ($ & ~FF_FRAMEMASK)
		end
		
		if mo.target.eflags & MFE_UNDERWATER
			local fuk = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_PARTICLE)
			fuk.tics = 35
			fuk.scale = 1
			fuk.destscale = mo.scale*5
			fuk.scalespeed = mo.scale/12
			fuk.fuse = 18
			fuk.momz = FixedMul(mo.target.scale, 2*FRACUNIT)
			P_RemoveMobj(mo)
		end
		
		if mo and mo.valid and not (mo.target.player.blazehover)
			P_RemoveMobj(mo)
		end
		
		if mo and mo.valid and P_PlayerInPain(mo.target.player)
			P_RemoveMobj(mo)
		end
	else
		P_RemoveMobj(mo)
	end	
end, MT_BLAZE_HOVERFIRE)

--Blaze's Tail
--Fuck followmobjs btw, they are dumb and bad
local standframe = {
  [SPR2_STND] = true,
  [SPR2_WALK] = true,
  [SPR2_WAIT] = true,
  [SPR2_SKID] = true,
  [SPR2_RIDE] = true,
}
local runframe = {
  [SPR2_RUN_] = true,
  [SPR2_GLID] = true,
  [SPR2_TWIN] = true,
  [SPR2_EDGE] = true,
}
local fallframe = {
  [SPR2_FALL] = true,
  [SPR2_SPIN] = true
}
local springframe = {
  [SPR2_SPNG] = true,
  [SPR2_GASP] = true
}

local rollframe = {
	[SPR2_ROLL] = true
}

--tail thinker
addHook("FollowMobj", function(p, mobj)
	if not (p.mo and p.mo.valid and p.mo.health and p.mo.skin == "blaze" and p.solchar) return end
	local sprite2 = p.mo.sprite2 & ~FF_SPR2SUPER
	mobj.skin = "blaze"
	if p.mo.flags2 & MF2_OBJECTFLIP
		mobj.flags2 = $ | MF2_OBJECTFLIP
	else
		mobj.flags2 = $ & ~ MF2_OBJECTFLIP
	end
	if (sprite2 == SPR2_ROLL)
		if P_MobjFlip(p.mo) == 1
			P_TeleportMove(mobj, p.mo.x, p.mo.y, p.mo.z)
		else
			P_TeleportMove(mobj, p.mo.x, p.mo.y, p.mo.z+p.mo.height-mobj.height)
		end
	else
		Blaze_MoveTail(p, mobj)
	end
	mobj.flags2 = $|MF2_LINKDRAW
	mobj.color = p.mo.color
	if not (p.solchar.istransformed == 1)
		if standframe[sprite2]
			if mobj.state != S_BLAZETAIL_STAND
				mobj.state = S_BLAZETAIL_STAND
			end
		elseif runframe[sprite2]
			if mobj.state != S_BLAZETAIL_RUN
				mobj.state = S_BLAZETAIL_RUN
			end
		elseif fallframe[sprite2] 
			if mobj.state != S_BLAZETAIL_FALL
				mobj.state = S_BLAZETAIL_FALL
			end
		elseif springframe[sprite2] 
			if mobj.state != S_BLAZETAIL_SPRING
				mobj.state = S_BLAZETAIL_SPRING
			end
		elseif rollframe[sprite2] --and not (p.powers[pw_underwater])
			if mobj.state != S_PLAY_ROLL
				mobj.state = S_PLAY_ROLL
			end
			mobj.frame = p.mo.frame
			mobj.sprite2 = SPR2_FIRE
			mobj.flags2 = $&~MF2_LINKDRAW
			mobj.color = p.blazeflamecolor
			
		elseif mobj.state != S_BLAZETAIL_INVIS
			mobj.state = S_BLAZETAIL_INVIS
		end
	else
		mobj.state = S_BLAZETAIL_INVIS
	end
	if (p.mo.flags2 & MF2_DONTDRAW)
		mobj.flags2 = $|MF2_DONTDRAW
	else
		mobj.flags2 = $&~MF2_DONTDRAW
	end
	if mobj.sprite2 == SPR2_STND
		if p.mo.state == S_PLAY_JUMP or p.mo.state == TWIRLSTATE
			if mobj.anim_duration > 1
				mobj.anim_duration = 1
			end
		else
			if mobj.anim_duration > 4
				mobj.anim_duration = 4
			end
		end
	end
	mobj.spritexscale = p.mo.spritexscale
	mobj.spriteyscale = p.mo.spriteyscale
	mobj.rollangle = p.mo.rollangle
	mobj.scale = p.mo.scale
	
	// Lach: also copy render & frame flags
	mobj.frame = ($ & (FF_FRAMEMASK|FF_ANIMATE)) | (p.mo.frame & ~(FF_FRAMEMASK|FF_ANIMATE))
	if rollframe[sprite2]
		mobj.frame = $|FF_FULLBRIGHT
	end
	mobj.renderflags = p.mo.renderflags
	return true
end, MT_BLAZETAIL)

--damage enemies with the hover fire!
local function collZCheck(m,n) return m.z-15*m.scale < n.z+n.height and m.z+m.height-15*m.scale > n.z end
addHook("MobjMoveCollide", function(thing, tmthing)
	if thing and thing.valid and tmthing and tmthing.valid and tmthing.health and tmthing != thing.target
		if collZCheck(thing, tmthing)
			P_DamageMobj(tmthing, thing, thing.target, DMG_FIRE)
		end
	end
end, MT_BLAZE_HOVERFIRE)

--spindash schtuff
addHook("SpinSpecial", function(player)
	if player.mo.skin == "blaze" and player.panim != PA_PAIN and P_IsObjectOnGround(player.mo)
	and player.speed <= FixedMul(4*FRACUNIT+FRACUNIT/2, player.mo.scale) and player.mo.state != S_PLAY_ROLL
		if player.powers[pw_carry] return end
		if player.exiting return end
		if not (player.pflags&PF_SPINDOWN) and not player.blazespindash
			player.blazedashspeed = 15*FRACUNIT
			player.pflags = $|PF_STARTDASH
			player.mo.state = S_PLAY_BLAZE_SPINDASH
			player.blazespindash = 1
			S_StartSound(player.mo, sfx_spndsh)
		end
		return true
	end
end)

--spindash thinker
addHook("PlayerThink", function(player)
	if player.mo and player.mo.skin == "blaze"
		if player.mo.blazefirebullshit == nil
			player.mo.blazefirebullshit = 0
		end
		if player.mo.blazeisabitchassmotherfucker
			player.mo.blazefirebullshit = $ + 1
		else
			player.mo.blazefirebullshit = 0
		end
		player.mo.blazeisabitchassmotherfucker = false
		
		if player.blazespindash
			if player.blazespindash == -1 or player.powers[pw_carry]
			or P_PlayerInPain(player) or not player.mo.health
				player.blazespindash = 0
				
			--charging
			elseif player.cmd.buttons & BT_SPIN
				if player.mo.state != S_PLAY_BLAZE_SPINDASH and P_IsObjectOnGround(player.mo)
					player.mo.state = S_PLAY_BLAZE_SPINDASH
				end
				player.pflags = $|PF_STARTDASH
				--player.normalspeed = 0
				player.mo.momx = 0
				player.mo.momy = 0
				player.blazewasdashing = true
				player.powers[pw_noautobrake] = 1
				player.drawangle = player.mo.angle
				if not P_IsObjectOnGround(player.mo)
					player.blazespindash = 0
					player.pflags = $ & ~ PF_STARTDASH
					
				end
				local chargecalculation = (6*(player.blazedashspeed  - (player.mindash)))/((player.maxdash) - (player.mindash))
				player.blazedashspeed = min(max($+FRACUNIT, player.mindash), player.maxdash)
				local soundcalculation = (6*(player.blazedashspeed  - (player.mindash)))/((player.maxdash) - (player.mindash))
				if not player.spectator and soundcalculation != chargecalculation
					S_StartSound(player.mo, sfx_spndsh)
				end
			
			--zoom off!
			elseif not (player.cmd.buttons&BT_SPIN)
				P_InstaThrust(player.mo, player.mo.angle, FixedMul(player.blazedashspeed , player.mo.scale))
				S_StartSound(player.mo, sfx_s23c)
				player.pflags = $|PF_SPINNING&~PF_THOKKED&~PF_STARTDASH
				player.blazespindash = -1
				if player.mo.momz*P_MobjFlip(player.mo) < 0
					player.mo.momz = 0
				end
				player.mo.state = S_PLAY_ROLL
				player.fuckyougame = true
				player.blazelaststate = S_PLAY_ROLL
				--player.normalspeed = skins[player.mo.skin].normalspeed
				player.blazewasdashing = false
			else
				player.blazespindash = 0
			end
		elseif player.blazewasdashing
			--player.normalspeed = skins[player.mo.skin].normalspeed
			player.blazewasdashing = false
		end
	end
end)

--allow going under spin gaps while spinning
addHook("PlayerHeight", function(p)
	if p.mo and p.mo.skin == "blaze"
		if p.mo.state == S_PLAY_ROLL or p.mo.state == S_PLAY_BLAZE_SPIN
			return p.spinheight
		end
	end
end)
addHook("PlayerCanEnterSpinGaps", function(p)
	if p.mo and p.mo.skin == "blaze"
		if p.mo.state == TWIRLSTATE or p.mo.state == S_PLAY_BLAZE_SPIN
			if p.mo.state != S_PLAY_BLAZE_SPIN
				p.mo.state = S_PLAY_BLAZE_SPIN
			end
			p.pflags = $ | PF_JUMPSTASIS
			p.mo.blazeinspingap = 15
			return true
		end
	end
end)

--partial fire immunity
addHook("ShouldDamage", function(mo, inf, src, dmg, dmgt)
    if mo and mo.player and mo.skin == "blaze"
        if not dmgt == DMG_FIRE return end
        if mo.player.powers[pw_invulnerability] return end
        if mo.player.powers[pw_flashing] return end
		if (mo.player.gotflag or mo.player.gotflagdebuff or mo.player.gotcrystal) return end
		if ((inf and inf.valid and inf.player) or (src and src.valid and src.player)) return end
        if (mo.player.powers[pw_shield] & SH_PROTECTFIRE) return end
        if mo.player.solchar and mo.player.solchar.istransformed return end
        if mo.player.exiting return end
        if mo.boat and mo.boat.valid and mo.boat.health return end
        if inf and inf.valid and inf.flags & MF_FIRE
            if leveltime % 5 == 0
                local flame = P_SpawnMobjFromMobj(mo, P_RandomRange(-35, 35)*FRACUNIT, P_RandomRange(-35, 35)*FRACUNIT, P_RandomRange(-15, 15)*FRACUNIT, MT_PARTICLE)
                flame.state = S_FLAME
                flame.scale = mo.scale/4
                flame.fuse = 40
            end
            return false
        elseif not (inf or src) and dmgt == DMG_FIRE
            mo.blazeisabitchassmotherfucker = true
            if mo.player.rings > 1
                if mo.blazefirebullshit % 15 == 0
                    mo.player.rings = $ - 1
                    S_StartSound(mo, sfx_antiri)
                end
                if leveltime % 5 == 0
                    local flame = P_SpawnMobjFromMobj(mo, P_RandomRange(-35, 35)*FRACUNIT, P_RandomRange(-35, 35)*FRACUNIT, P_RandomRange(-15, 15)*FRACUNIT, MT_PARTICLE)
                    flame.state = S_FLAME
                    flame.scale = mo.scale/4
                    flame.fuse = 40
                end
                return false
            end
        end
    end
end, MT_PLAYER)

addHook("MobjDeath", function(trg, inf, src)
	if not (trg.flags & MF_ENEMY) return end
	if trg and trg.valid and inf and inf.valid and inf.health and inf.player and inf.skin == "blaze" and inf.player.blazeboosting
		local p = inf.player
		
		S_StartSound(inf, sfx_s3k49)
		trg.flags2 = $|MF2_DONTDRAW
	//	mobjinfo[MT_BOWSER_FLING].spawnstate = trg.state --Copying it's spawnstate also copies that state's action , that's BEGGING for weird behaviour.
		local fling = P_SpawnMobjFromMobj(trg, 0, 0, 0, MT_BLAZE_FLING)
		if fling and fling.valid and trg and trg.valid --fucking errors for some reason if i dont do this shit
		
		--update: it still FUCKING DOES EVEN IF I DO ADD THESE CHECKS WHAT THE HELL AM I DOING WRONG FUCK
		
			trg.tics = -1
			fling.sprite = trg.sprite --Whatever sprite it's using now.
			fling.sprite2 = trg.sprite2 --just incase it's a player somehow.
			fling.frame = trg.frame --The frame it just used
			fling.angle = trg.angle --The angle it just used
			fling.color = trg.color
			fling.info.deathstate = S_CYBRAKDEMONVILEEXPLOSION1  --I'd recommend this, but for now, let's keep the deathstate behaviour, I guess!
			--fling.info.deathstate = trg.info.deathstate
			fling.nokilltimer = 3
			fling.info.deathsound = sfx_s3kb4
			S_StopSound(trg)
			--print("huhjnjdf")
			P_SetObjectMomZ(fling, 15*FRACUNIT, false)
			P_InstaThrust(fling, R_PointToAngle2(inf.x, inf.y, fling.x, fling.y), 63*FRACUNIT)
			--local storespawnhealth = trg.info.spawnhealth
			--trg.type = MT_BOWSER_DEADFLING
			--trg.info.spawnhealth = storespawnhealth
		end
	end
end)
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health
		if not (mo.secondphase)
			if mo.nokilltimer > 0
				mo.nokilltimer = $ - 1
			end
			--print(mo.info.deathstate)
			if P_IsObjectOnGround(mo) or (FixedHypot(mo.momx, mo.momy) == 0)
				--mo.rollangle = 0
				if mo.nokilltimer == 0
					mo.momx = 0
					mo.momy = 0
					mo.momz = 0
					mo.flags = $ | MF_NOGRAVITY
					local lmao = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BLAZE_FLING)
					lmao.sprite = mo.sprite
					lmao.sprite2 = mo.sprite2
					lmao.color = mo.color
					lmao.target = mo
					lmao.secondphase = true
					lmao.rollangle = mo.rollangle
					lmao.angle = mo.angle
					P_KillMobj(mo)
					mo.rollangle = 0
				end
			else
				mo.rollangle = $ + FixedAngle(20*FRACUNIT)
			end
		else
			if not (mo.target and mo.target.valid)
				P_RemoveMobj(mo)
			else
				mo.momx = 0
				mo.momz = 0
				mo.momy = 0
				if leveltime % 2 == 0
					mo.flags2 = $|MF2_DONTDRAW
				else
					mo.flags2 = $&~MF2_DONTDRAW
				end
			end
		end
	end
end, MT_BLAZE_FLING)

addHook("JumpSpecial", function(player) //remove spin when jumping
	if (player.mo.skin == "blaze") and (player.pflags & PF_SPINNING) and ((player.mo.eflags & MFE_JUSTHITFLOOR) or P_IsObjectOnGround(player.mo)) and not (player.pflags & PF_JUMPDOWN) and not (player.pflags & PF_JUMPSTASIS)
		player.pflags = $ & ~PF_SPINNING
	end
end)
